<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        button {
            outline: none;
            border: none;
        }
        .snake-wrap {
            width: 600px;
            height: 720px;
            margin: 50px auto;
            background-color: lightblue;
            border: 1px solid #000;
        }
        .info-bd {
            height: 60px;
        }
        .info-bd .info-item {
            float: left;
            width: 50%;
            height: 100%;
            text-align: center;
            line-height: 60px;
            font-size: 20px;
            color: #fff;
        }
        .game-bd {
            height: 600px;
            background-color: #000;
        }
        .btn-group {
            height: 60px;
        }
        .btn-group .btn {
            float: left;
            width: 33.33%;
            height: 100%;
        }
        .btn-group .btn button{
            width: 100%;
            height: 100%;
            background-color: transparent;
            color: #fff;
            font-size: 20px;
            cursor: pointer;
        }
        .btn-group .btn button:hover {
            background-color: blue;
        }
        .btn-group .btn button:disabled {
            background-color: gray;
        }
    </style>
</head>
<body>
    <div class="snake-wrap">
        <div class="info-bd">
            <div class="info-item">
                得分：<span class="score">0</span>分
            </div>
            <div class="info-item">
                用时：<span class="second">0</span>秒
            </div>
        </div>
        <div class="game-bd">
            <canvas id="gameCan" width="600" height="600"></canvas>
        </div>
        <div class="btn-group">
            <div class="btn">
                <button class="j-start">开始</button>
            </div>
            <div class="btn">
                <button class="j-pause">暂停</button>
            </div>
            <div class="btn">
                <button class="j-reset">重置</button>
            </div>
        </div>
    </div>

    <script type="text/javascript">
        var can = document.getElementById('gameCan'),
            ctx = can.getContext('2d'),
            cWidth = ctx.canvas.width,
            cHeight = ctx.canvas.height,
            oSecond = document.getElementsByClassName('second')[0],
            oScore = document.getElementsByClassName('score')[0],
            oStart = document.getElementsByClassName('j-start')[0],
            oPause = document.getElementsByClassName('j-pause')[0],
            oReset = document.getElementsByClassName('j-reset')[0],
            r = 10,
            size = r * 2;
            t = null,
            st = null,
            bodyNum = 3,
            second = 0,
            score = 0;

        function Circle(x, y, color) {
            this.x = x;
            this.y = y;
            this.color = color;
        }

        Circle.prototype.draw = function() {
            ctx.fillStyle = this.color;

            ctx.beginPath();
            ctx.arc(this.x + r, this.y + r, r, 0, 2 * Math.PI, false);
            ctx.fill();
        }

        function Snake() {
            this.snakeArr = [];
            this.bodySize = this.snakeArr.length || bodyNum;
            this.dir = 'RIGHT';

            for (var i = 0; i < this.bodySize; i++) {
                this.snakeArr.push(
                    new Circle(0, i * r * 2, (i === this.bodySize - 1 ? 'red' : 'green'))
                );
            }
        }

        Snake.prototype.move = function() {
            var head = this.snakeArr[this.snakeArr.length - 1],
                snakeArr = this.snakeArr,
                _self = this;
                
            ctx.clearRect(0, 0, cWidth, cHeight);
            creaetFood(snakeArr)

            t = setInterval(function() {
                for (var i = 0; i < snakeArr.length; i++) {
                    ctx.clearRect(snakeArr[i].x, snakeArr[i].y, size, size);
                    if (i !== snakeArr.length - 1) {
                        snakeArr[i].x = snakeArr[i + 1].x
                        snakeArr[i].y = snakeArr[i + 1].y
                    }
                }

                if (_self.dir === 'DOWN') {
                    head.y = head.y == cHeight ? 0
                                            : head.y + size;
                } else if (_self.dir === 'UP') {
                    head.y = head.y == -size ? (cHeight - size)
                                            : head.y - size;
                } else if (_self.dir === 'RIGHT') {
                    head.x = head.x == (cWidth + size) ? 0
                                                    : head.x + size;
                } else if (_self.dir === 'LEFT') {
                    head.x = head.x == -size ? (cWidth - size)
                                            : head.x - size;
                }

                for (var i = 0; i < snakeArr.length; i++) {
                    snakeArr[i].draw();

                    // 自杀
                    if (i !== snakeArr.length - 1) {
                        if (head.x === snakeArr[i].x && head.y === snakeArr[i].y) {
                            clearInterval(t);
                            ctx.clearRect(0, 0, cWidth, cHeight);
                            alert('Game Over');
                            reset()
                            return;
                        }
                    }
                }

                // eat food
                if (s.foodX === head.x && s.foodY === head.y) {
                    var x,
                        y;

                    creaetFood(snakeArr);

                    if (snakeArr[0].x === snakeArr[1].x) {
                        x = snakeArr[0].x;
                        if (snakeArr[0].y > snakeArr[1].y) {
                            y = snakeArr[0].y + size;
                        } else if (snakeArr[0].y > snakeArr[1].y) {
                            y = snakeArr[0].y - size;
                        }
                    } else if (snakeArr[0].y === snakeArr[1].y) {
                        y = snakeArr[0].y;
                        if (snakeArr[0].x > snakeArr[1].x) {
                            x = snakeArr[0].x + size;
                        } else if (snakeArr[0].x > snakeArr[1].x) {
                            x = snakeArr[0].x - size;
                        }
                    }

                    // 在数组的第一位添加
                    snakeArr.unshift(new Circle(x, y, 'blue'));
                    score ++;
                    oScore.innerText = score;
                }
            }, 200);
        }

        document.onkeydown = function(e) {
            var e = e || window.event,
                code = e.keyCode;

            if (code === 38) { //up,如果正在向下运动，按上键是没有用的
                s.dir = s.dir !== 'DOWN' ? 'UP' : 'DOWN';
            } else if (code === 40) {
                s.dir = s.dir !== 'UP' ? 'DOWN' : 'UP';
            } else if (code === 37) {
                s.dir = s.dir !== 'RIGHT' ? 'LEFT' : 'RIGHT';
            } else if (code === 39) {
                s.dir = s.dir !== 'LEFT' ? 'RIGHT' : 'LEFT';
            }
        }

        function creaetFood(snakeArr) {
            s.foodX = setRandPos().x;
            s.foodY = setRandPos().y;

            for (var i = 0; i < snakeArr.length; i++) {
                if (s.foodX === snakeArr[i].x && s.foodY === snakeArr[i].y) {
                    s.foodX = setRandPos().x;
                    s.foodY = setRandPos().y;
                }
            }

            new Circle(s.foodX, s.foodY, 'yellow').draw();
        }

        function setRandPos() {
            var arr = [];

            for (var i = 0; i < cWidth - size; i++) {
                // size的倍数
                if (i % size === 0) {
                    arr.push(i);
                }
            }

            return {
                x: arr[Math.floor(Math.random() * arr.length + 1) - 1],
                y: arr[Math.floor(Math.random() * arr.length + 1) - 1]
            }
        }

        oStart.onclick = function() {
            start.call(this);
        }

        oPause.onclick = function() {
            pause.call(this);
        }

        oReset.onclick = function() {
            reset.call(this);
        }

        function start() {
            s.move();
            this.disabled = 'disabled';
            st = setInterval(function() {
                second ++;
                oSecond.innerText = second;
            }, 1000);
        }

        function pause() {
            clearInterval(st);
            clearInterval(t);
            oStart.disabled = '';
        }

        function reset() {
            clearInterval(st);
            clearInterval(t);
            oStart.disabled = '';
            oSecond.innerText = 0;
            oScore.innerText = 0;
            ctx.clearRect(0, 0, cWidth, cHeight);

            s = new Snake();//重新实例化
        }

        var s = new Snake()
    </script>
</body>
</html>